﻿package {
	import flash.display.*;
	import flash.events.*;
	import flash.text.*;
	import flash.geom.*;
	import flash.utils.Timer;
	import flash.media.*;
	import flash.net.*;
	import flash.ui.*;
	
	public class Whackamole extends MovieClip 
	{
		//game state
		private var room:Room;
		private var clockSpeed = 20;
		private var gameOver = true;
		private var timeBonusCounter = 0;
		private var gameOverText:TextField = new TextField();
		private var gameOverText2:TextField = new TextField();
		private var restartButton:TextField = new TextField();
		public static var scoreBox:ScoreBox;
		private var crossHair = new CrossHairSprite();
		
		private var addHumanCounter = 0;
		private var maxHumans:int = 20;
		private var currentHumanCount:int = 0;
		private var wave:Array = null;
		private var maxWaves = 2;
		private var currentWaveCount = 0;

		private var zombieMagazine:Array = null;		
		
		private var zombieCount:int = 10;
		private var currentZombieCount:int = 0;
		private var zombieHorde:Array = null;
		
		private var regionSet:RegionSet = null;
		
		private var cannon = new Cannon();
		
		private var startGameSprite = new StartGameSprite();
		private var introSprite = new IntroSprite();
		private var endOfLevelSprite = new EndOfLevelSprite();
		
		private var aGameStatus:String;
		
		public function Whackamole() 
		{
			init();
			main();
		}
		
		public function init() 
		{	
			stage.stageWidth = 1000;
			stage.stageHeight = 750;
			stage.stageFocusRect = false;

			addChild(new BackgroundSprite);
			room = new Room();
			room.x = 10 + (stage.stageWidth / 2) - (room.width / 2);
			room.y = 10;
			addChild(room);
		
			regionSet = new RegionSet();
			regionSet.setup(3, 3, room.rectangle.width, room.rectangle.height);		

			
			for (var i=1;i<10;i++){
				var rect = regionSet.getRegion(i).getRectangle();
				room.rectangle.addChild(rect);
			}
			
			Mouse.hide();
			stage.addEventListener(MouseEvent.CLICK, clickHandler);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
			stage.addChild(crossHair);
			
			cannon.x = room.width / 2;
			cannon.y = stage.stageHeight - (cannon.height-10);
			
			room.addChild(cannon);
			
			endOfLevelSprite.x = (room.rectangle.width - endOfLevelSprite.width) / 2;
			endOfLevelSprite.y = (room.rectangle.height - endOfLevelSprite.height) / 2;
			
			startGameSprite.x = (room.rectangle.width - startGameSprite.width) / 2;
			startGameSprite.y = (room.rectangle.height - startGameSprite.height) / 2;
			
			scoreBox = new ScoreBox();
			scoreBox.x = (stage.stageWidth / 2) - (scoreBox.width / 2);
			scoreBox.y = cannon.y + (cannon.height / 2) + 30;
			addChild(scoreBox);
			
			scoreBox.setZombiesRemaining(zombieCount);
			
			showSplashScreen();
		}
		
		private function showSplashScreen()
		{
			room.addChild(startGameSprite);
			stage.addEventListener(KeyboardEvent.KEY_UP, splashScreenHandler);			
		}
		
		private function splashScreenHandler(event:KeyboardEvent)
		{
			var letter = String.fromCharCode(event.charCode);
			//trace("letter pressed: "+letter);
			
			switch(letter)
			{
				case "u" :
				case "i" :
					startGameSprite.addChild(introSprite);
					introSprite.gotoAndPlay(1);
					break;
				default :
					startGame();
					break;
			}
		}
		
		private function startGame()
		{
			stage.removeEventListener(KeyboardEvent.KEY_UP, splashScreenHandler);
			stage.removeEventListener(KeyboardEvent.KEY_UP, startGame);
			stage.addEventListener(Event.ENTER_FRAME, enterFrame);
			
			room.addEventListener("cannonFired", hurlZombie);
			
			room.removeChild(startGameSprite);
			
			newWave();
		}
		
		private function enterFrame(event:Event)
		{
			var nextWave = new Array();
			var deadCount = 0;
			var safeCount = 0;
			addHumanCounter++;
			
			if((addHumanCounter >= Math.random()*30))
			{
				if(currentHumanCount > 0)
				{
//					wave.push(getRandomHuman());
					wave.push(getCarParkHuman());
					currentHumanCount--;
				}
				
				addHumanCounter = 0;
			}
			
			//Move all the humans calling moveMe on them. 
			for each (var human in wave)
			{
				if(human.x < 0)
				{
					room.removeChild(human);
					scoreBox.incrementHumansSaved(1);
					scoreBox.incrementHumansScore(human.getScore());
					safeCount++;
				}
				else 
				{
					var isHumanAlive = true;

					for each (var z in zombieHorde)
					{
						if (z.canAttack(human))
						{
							scoreBox.incrementHumansTurned(1);
							scoreBox.incrementZombiesScore(human.getScore());
							room.removeChild(human);
							var newZombie = new Zombie();
							newZombie.x = human.x;
							newZombie.y = human.y;
							zombieHorde.push(newZombie);
							room.addChild(newZombie);
							isHumanAlive = false;
							break;
						}
					}
					
					if (isHumanAlive)
					{
						human.checkZombies(zombieHorde);
						
						if(human.x > room.rectangle.width && !human.isLooting && !human.gotLoot)
						{
							human.isLooting = true;
						}
						
						human.step();
						nextWave.push(human);
					}
					else
					{
						deadCount++;
					}
				}
			}
			
			wave = nextWave;

			if(currentHumanCount == 0 && wave.length == 0)
			{
				endOfLevel();
			}
			else
			{				
				var currentHorde:Array = new Array();
				
				for each (var zombie in zombieHorde)
				{
					zombie.step();
					if (zombie.isAlive)
					{
						currentHorde.push(zombie);					
					}
				}
				
				zombieHorde = currentHorde;
			}
		}
		
		public function endOfLevel()
		{
			room.removeEventListener(KeyboardEvent.KEY_UP, keyHandler);
			cleanUp();
			
			if (currentWaveCount < maxWaves)
			{
				showScore();
			} else 
			{
				endGame();
			}
		}
		
		public function showScore()
		{
			room.addChild(endOfLevelSprite);
			room.addEventListener(KeyboardEvent.KEY_UP, startLevel);
		}
			
		public function endGame()
		{
			stage.removeEventListener(Event.ENTER_FRAME, enterFrame);
			currentWaveCount = 0;
			showSplashScreen();
		}
	
		private function startLevel(event:KeyboardEvent)
		{
			room.removeEventListener(KeyboardEvent.KEY_UP, startLevel);
			room.removeChild(endOfLevelSprite);
			newWave();
		}
		
		public function getSupermarketHuman()
		{
			return getNewHuman(room.rectangle.width, true);
		}

		public function getCarParkHuman()
		{
			return getNewHuman(0, true);
		}
		
		public function getNewHuman(startX, isMirrored)
		{
			var human = new Human();
			
			human.stepX = -1;
			human.gotLoot = false;
			
			var multiplyer = 1.5;
			var rand = Math.random();
			//trace(rand);//TMP
			if(rand < 0.33)
			{
				multiplyer = 0.5;
			}
			else if (rand > 0.66)
			{
				multiplyer = 2.5;
			}
			
			human.x = startX;
			human.y = (room.rectangle.height / 3) * multiplyer;
			
			room.addChild(human);
			
			return human;
		}
		
		public function main() 
		{
			restartGame();
		}
		
		private function newWave()
		{
			wave = new Array();
			
			currentHumanCount = maxHumans;
			currentZombieCount = 0;
			
			zombieMagazine = new Array();

			for (var i=0; i<zombieCount; i++)
			{
				var zombie = new Zombie();
				zombie.scaleX = zombie.scaleY = 0.4;
				zombie.x = (room.x + (i * 20)) - 200;
				zombie.y = room.height - zombie.height;
				zombieMagazine.push(zombie);
				room.addChild(zombie);
			}
			
			scoreBox.setZombiesRemaining(zombieCount);
			
			room.addEventListener(KeyboardEvent.KEY_UP, keyHandler);
			stage.focus = room;
			
			currentWaveCount++;
		}
		
		public function cleanUp()
		{
			for each (var zombie in zombieHorde)
			{
				room.removeChild(zombie);
			}
			
			for each (var human in wave)
			{
				room.removeChild(human);
			}
			
			for (var i = zombieMagazine.length; i > 0; i--)
			{
				room.removeChild(zombieMagazine.pop());
			}
			
			wave = new Array();
			zombieHorde = new Array();
		}
		
		public function stopGame()
		{
			gameOver = true;			
			room.clearContents();

			var format = new TextFormat();
			format.size = 64;
			gameOverText.text = gameOverText2.text = "GAME OVER!";
			gameOverText.textColor = 0xFFFFFF;
			gameOverText2.textColor = 0x00000;
			gameOverText.setTextFormat(format);
			gameOverText2.setTextFormat(format);
			gameOverText.autoSize = TextFieldAutoSize.CENTER;
			gameOverText2.autoSize = TextFieldAutoSize.CENTER;
			gameOverText.x = room.x + (room.rectangle.width / 2) - (gameOverText.width / 2);
			gameOverText.y = room.y + (room.rectangle.height / 2) - (gameOverText.height / 2);
			gameOverText2.x = gameOverText.x - 2;
			gameOverText2.y = gameOverText.y - 2;

			format.size = 20;
			
			restartButton.text = "RESTART";
			restartButton.textColor = 0xFFFFFF;
			format.size = 18;
			restartButton.setTextFormat(format);
			restartButton.autoSize = TextFieldAutoSize.CENTER;
			restartButton.border = true;
			restartButton.borderColor = 0xFFFFFF;
			restartButton.background = true;
			restartButton.backgroundColor = 0x000000;
			restartButton.selectable = false;
			restartButton.x = room.x + (room.rectangle.width / 2) - (restartButton.width / 2);
			restartButton.y = (room.y + (room.rectangle.height / 2) - (restartButton.height / 2)) + 80;
			restartButton.addEventListener(MouseEvent.CLICK, restartButtonClick);
		
			this.addChild(restartButton);				
			this.addChild(gameOverText2);
			this.addChild(gameOverText);
		}

		public function restartGame()
		{
			if(this.contains(gameOverText))
			{
				this.removeChild(gameOverText);
			}
			if(this.contains(gameOverText2))
			{
				this.removeChild(gameOverText2);
			}
			if(this.contains(restartButton))
			{
				this.removeChild(restartButton);
			}
			
			gameOver = false;
		}
		
		// send a 'step' event to all NPCs
		private function step(event:TimerEvent)
		{
			var i:int;
			var s:Sprite;
			var sprites = new Array();

			for (i = 0; i < room.numChildren; i++)
			{
				s = room.getChildAt(i) as Sprite;
			}
			
			checkGameState(event);
		}
		
		function sortOnYaxis(a:Sprite, b:Sprite):Number
		{
			if(a.y > b.y) {
				return 1;
			} else if(a.y < b.y) {
				return -1;
			} else  {
				return 0;
			}
		}
		
		public function checkGameState(event)
		{
			var gameEnd = false;
			
			if (gameEnd) // display game over text
			{
				trace("GAME OVER");//TMP
				
				this.stopGame();				
			}
		}
		
		private function restartButtonClick(e:MouseEvent) {
            restartGame();
        }
		
		private function aimAndFire(regionNumber)
		{
			trace("Region: "+regionNumber);//TMP
			var region = regionSet.getRegion(regionNumber);
			
			var coords = region.getCentre();
			coords['x'] += room.x;
//			trace("coords: "+coords['x']+", "+coords['y']);//TMP
			
			cannon.aimAndFire(coords);
		}
		
		private function hurlZombie(event:Event)
		{
			var zombie = new Zombie();
			var startCoords = cannon.getCannonLoudEndCoords();
			zombie.x = startCoords["x"];
			zombie.y = startCoords["y"];
			
			room.addChildAt(zombie, 1);	
//			room.setChildIndex(zombie, 1);			
			
			var targetCoords = cannon.getTargetCoords();
			targetCoords['x'] -= room.x;
			
			zombieHorde.push(zombie);			

			zombie.hurlTo(targetCoords);

			currentZombieCount++;
			
			room.removeChild(zombieMagazine.pop());
			
			for (var i = 0; i < zombieMagazine.length; i++)
			{
				zombieMagazine[i].x += 20;
			}
			
			scoreBox.setZombiesRemaining(zombieCount - currentZombieCount);			
		}

		private function keyHandler(event:KeyboardEvent)
		{
			var letter = String.fromCharCode(event.charCode);
			trace("key pressed: "+letter);//TMP
			var items = null;
			
			if(!isNaN(letter) && letter != "0")
			{
				//trace("current zombie count: "+currentZombieCount+" zombie count: "+zombieCount);//TMP
				if (currentZombieCount < zombieCount)
				{
					aimAndFire(int(letter));
				}
			}
		}
		
		private function mouseMoveHandler(event:MouseEvent)
		{
			crossHair.x = event.stageX;
			crossHair.y = event.stageY;
		}
		
		public function clickHandler(event:MouseEvent)
		{
			crossHair.gotoAndPlay(2);
			stage.focus = room;	
			
			for each (var zombie in zombieHorde)
			{
				if (zombie.isAlive)
				{
					if (zombie.hitTestPoint(event.stageX, event.stageY, true))
					{
						zombie.die();
						break;
					}
				}
			}
		}
				
	}
}